/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

#define UART_RECV_BUF_LEN   64

enum{
	UTILS_ALERM_TIMER = 0, //闹钟定时器
	UTILS_UART_PROC
};

typedef struct DATA_ALERM_TIM{
	uint8_t isRunning; //是否正在运行
	uint16_t TimeLeft; //倒计时时间
	uint16_t TimeTotal; //倒计时设置的时间
}DATA_ALERM_TIM_t;

typedef struct DATA_UART_PROC{
	uint32_t ticksLastChar; //上一个字符的接收时间
	uint32_t ticksNow;
	uint8_t recvBuf[UART_RECV_BUF_LEN];
	int recvAvail; //接收到的有效数据
	int screenScrollTicks; //屏幕滚动时间戳
	int screenScrollEnable;
}DATA_UART_PROC_t;

#define LED4_ON()  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7,GPIO_PIN_SET)
#define LED4_OFF()  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7,GPIO_PIN_RESET)

#define LED5_ON()  HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1,GPIO_PIN_SET)
#define LED5_OFF()  HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1,GPIO_PIN_RESET)

#define LED6_ON()  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11,GPIO_PIN_SET)
#define LED6_OFF()  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11,GPIO_PIN_RESET)

#define LED7_ON()  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10,GPIO_PIN_SET)
#define LED7_OFF()  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10,GPIO_PIN_RESET)

#define IS_KEY3_PRESSED()  (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_9) == GPIO_PIN_RESET)
#define IS_KEY4_PRESSED()  (HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_2) == GPIO_PIN_RESET)
#define IS_KEY5_PRESSED()  (HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_1) == GPIO_PIN_RESET)
#define IS_KEY6_PRESSED()  (HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_0) == GPIO_PIN_RESET)

void SystemClock_Config(void);



uint8_t pic_r1[34]={0xAA,0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x1F,
					0xFA,0x47,0xF9,0x37,0xF8,0x37,0xF8,0x37,0xE1,0xE7,0xF6,0x0F,
					0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

uint8_t zh_num_4[34] ={0xAA,0x55,0xFF,0xFF,0xFF,0xFF,0x80,0x03,0xBB,0xBB,0xBB,0xBB,
				       0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xB7,0xBB,0xB7,0xC3,0xAF,0xFB,
					   0x9F,0xFB,0xBF,0xFB,0x80,0x03,0xBF,0xFB,0xFF,0xFF};/*"四",0*/

uint8_t text_clear[34]={0xAA,0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
						0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
						0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

uint8_t text_full[34]={0xAA,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
					   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
					   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};


static uint8_t gSegMap[10] = {0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xE0,0xFE,0xF6};
static int gBeepTimeout = 0;
static uint8_t gKeyState;
static DATA_ALERM_TIM_t gAlermTime;
static DATA_UART_PROC_t gUartProc;
static int gWorkMode = 0;

void BeepOn(int timeout){
	if (gBeepTimeout > 0){
		gBeepTimeout = timeout;
	} else{
		gBeepTimeout = timeout;
		HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
	}
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)
	{
		//printf("mode=%d, running=%d, left=%d\r\n", gWorkMode, gAlermTime.isRunning, gAlermTime.TimeLeft);

		if (gWorkMode == UTILS_ALERM_TIMER){
			if (gAlermTime.isRunning == 1){
				if (gAlermTime.TimeLeft > 0){
					gAlermTime.TimeLeft--;
					if (gAlermTime.TimeLeft == 0){
						//定时时间到了
						gAlermTime.isRunning = 0;

						//闹钟时间到了，一直叫
						BeepOn(0);
					}

					uint8_t buf[8];
					buf[0] = gSegMap[gAlermTime.TimeLeft/10];
					buf[1] = gSegMap[gAlermTime.TimeLeft%10];
					HAL_I2C_Mem_Write(&hi2c1,0x70, 0x10, 1, buf, 2, 100);
				}
			}
		} else if (gWorkMode == UTILS_UART_PROC) {
			if (gUartProc.screenScrollEnable == 1){
				uint8_t disp[34]={0xAA,0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
						0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
						0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
				int line = gUartProc.screenScrollTicks % 16;
				int i, idx=2;

				printf("line=%d\r\n", line);

				for(i=line*2; i<32; i += 2){
					disp[idx++] = zh_num_4[i+2];
					disp[idx++] = zh_num_4[i+3];
				}

				HAL_I2C_Master_Transmit(&hi2c1, 0xA0, (uint8_t*)disp, 34,  1000);

				gUartProc.screenScrollTicks++;
			}
		}
	} else if(htim->Instance == TIM5){

		if (gBeepTimeout > 0){
			gBeepTimeout -= 100;
			if (gBeepTimeout <= 0){
				//beep时间超时了
				HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_1);
			}
		}

	}
}

uint8_t ScanKeyLoop(){

	uint8_t keyEvent = 0; //按键事件

	if ((gKeyState & 0x01) == 0){
		if (IS_KEY3_PRESSED()){
			//消抖
			HAL_Delay(10);
			if (IS_KEY3_PRESSED()){
				gKeyState |= 0x01;
				keyEvent |= 0x01;
			}
		}
	} else{
		//按下状态
		if (!IS_KEY3_PRESSED()){
			//松开事件
			gKeyState &= ~0x01;
			keyEvent |= 0x10;
		}
	}


	if ((gKeyState & 0x02) == 0){
		if (IS_KEY4_PRESSED()){
			//消抖
			HAL_Delay(10);
			if (IS_KEY4_PRESSED()){
				gKeyState |= 0x02;
				keyEvent |= 0x02;
			}
		}
	} else{
		//按下状态
		if (!IS_KEY4_PRESSED()){
			gKeyState &= ~0x02;
			keyEvent |= 0x20;
		}
	}

	if ((gKeyState & 0x04) == 0){
		if (IS_KEY5_PRESSED()){
			//消抖
			HAL_Delay(10);
			if (IS_KEY5_PRESSED()){
				gKeyState |= 0x04;
				keyEvent |= 0x04;
			}
		}
	} else{
		//按下状态
		if (!IS_KEY5_PRESSED()){
			gKeyState &= ~0x04;
			keyEvent |= 0x40;
		}
	}

	if ((gKeyState & 0x08) == 0){
		if (IS_KEY6_PRESSED()){
			//消抖
			HAL_Delay(10);
			if (IS_KEY6_PRESSED()){
				gKeyState |= 0x08;
				keyEvent |= 0x08;
			}
		}
	} else{
		//按下状态
		if (!IS_KEY6_PRESSED()){
			gKeyState &= ~0x08;
			keyEvent |= 0x80;
		}
	}

	return keyEvent;
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (gUartProc.recvAvail < UART_RECV_BUF_LEN - 1){
		gUartProc.recvBuf[gUartProc.recvAvail + 1] = '\0';
		gUartProc.recvAvail++;

		//记录下最近一个命令的时间
		gUartProc.ticksLastChar = gUartProc.ticksNow; //记录下最近的收到的时间
		HAL_UART_Receive_IT(&huart4,  (unsigned char *)&(gUartProc.recvBuf[gUartProc.recvAvail]), 1);
	}
}

void trim(char* text){
	int len = strlen(text);
	int i;
	for(i=len-1; i>=0; i--){
		if ((text[i] == '\r')
			||(text[i] == '\n')
			||(text[i] == '\t')
			||(text[i] == ' ')){
			text[i]='\0';
		} else{
			return;
		}
	}
}

int main(void)
{
	uint8_t keyEvent;
	uint8_t buf[8];
	int i;

	HAL_Init();

	if(IS_ENGINEERING_BOOT_MODE())
	{
		/* Configure the system clock */
		SystemClock_Config();
	}

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_I2C1_Init();
	MX_TIM4_Init();
	MX_UART4_Init();
	MX_TIM3_Init();
	MX_TIM5_Init();

	//游戏开始
	printf("misc tools start...\r\n");

	gKeyState = 0;
	gWorkMode = UTILS_UART_PROC; //闹钟实验

	//------设置闹钟模式默认参数---------
	memset(&gAlermTime, 0, sizeof(gAlermTime));
	gAlermTime.TimeTotal = 60;
	if (gWorkMode == UTILS_ALERM_TIMER){
		for(i=0; i<8; i++){
			buf[i]=0x00;
		}
		buf[2] = gSegMap[gAlermTime.TimeTotal/10];
		buf[3] = gSegMap[gAlermTime.TimeTotal%10];
		HAL_I2C_Mem_Write(&hi2c1,0x70, 0x10, 1, buf, 8, 100);
	}

	//初始化
	memset(&gUartProc, 0, sizeof(gUartProc));
	if (gWorkMode == UTILS_UART_PROC){
		for(i=0; i<8; i++){
			buf[i]=0x00;
		}
		HAL_I2C_Mem_Write(&hi2c1,0x70, 0x10, 1, buf, 8, 100);

		//
		gUartProc.recvAvail = 0;
		HAL_UART_Receive_IT(&huart4,  (unsigned char *)gUartProc.recvBuf, 1);
	}

	HAL_I2C_Master_Transmit(&hi2c1, 0xA0, (uint8_t*)text_clear, 34,  1000);

	HAL_TIM_Base_Start_IT(&htim3);
	HAL_TIM_Base_Start_IT(&htim5);
	BeepOn(1000);

	while (1)
	{
		HAL_Delay(1);

		keyEvent = ScanKeyLoop();

		if ((keyEvent & 0x0F) != 0x00){
			BeepOn(200);
		}

		//
		if (gWorkMode == UTILS_ALERM_TIMER){
			//key3是启动定时器，Key4是停止闹钟, key5：闹钟时间增加1s, key6是停止闹钟

			if (keyEvent == 0x01){
				//按下key3, 如果没有开始闹钟，就进入
				if (gAlermTime.isRunning == 0){
					gAlermTime.TimeLeft = gAlermTime.TimeTotal; //60s倒计时

					buf[0] = gSegMap[gAlermTime.TimeLeft/10];
					buf[1] = gSegMap[gAlermTime.TimeLeft%10];

					buf[2] = gSegMap[gAlermTime.TimeLeft/10];
					buf[3] = gSegMap[gAlermTime.TimeLeft%10];
					HAL_I2C_Mem_Write(&hi2c1,0x70, 0x10, 1, buf, 4, 100);

					gAlermTime.isRunning = 1;
				}
			} else if (keyEvent == 0x02){ //如果闹钟正在运行，就停止
				if (gAlermTime.isRunning == 1){
					for(i=0; i<8; i++){
						buf[i]=0x00;
					}
					buf[2] = gSegMap[gAlermTime.TimeTotal/10];
					buf[3] = gSegMap[gAlermTime.TimeTotal%10];
					HAL_I2C_Mem_Write(&hi2c1,0x70, 0x10, 1, buf, 8, 100);

					gAlermTime.isRunning = 0;
					BeepOn(1000);
				}
			} else if (keyEvent == 0x04){
				//设置时间
				if (gAlermTime.isRunning == 0){

					gAlermTime.TimeTotal += 5;
					if (gAlermTime.TimeTotal > 90){
						gAlermTime.TimeTotal = 10;
					}

					buf[0] = gSegMap[gAlermTime.TimeTotal/10];
					buf[1] = gSegMap[gAlermTime.TimeTotal%10];
					HAL_I2C_Mem_Write(&hi2c1,0x70, 0x12, 1, buf, 2, 100);
				}
			}else if (keyEvent == 0x08){
				//设置时间
				if (gAlermTime.isRunning == 0){

					gAlermTime.TimeTotal -= 5;
					if (gAlermTime.TimeTotal < 10){
						gAlermTime.TimeTotal = 90;
					}

					buf[0] = gSegMap[gAlermTime.TimeTotal/10];
					buf[1] = gSegMap[gAlermTime.TimeTotal%10];
					HAL_I2C_Mem_Write(&hi2c1,0x70, 0x12, 1, buf, 2, 100);
				}
			}
		} else if (gWorkMode == UTILS_UART_PROC){
			gUartProc.ticksNow =  HAL_GetTick();

			if ((gUartProc.recvAvail > 0) && (gUartProc.ticksNow - gUartProc.ticksLastChar > 50)){
				int len;
				char recvCmd[64];

				//禁止中断
				HAL_UART_AbortReceive(&huart4);

				//禁止串口中断
				memcpy(recvCmd, gUartProc.recvBuf, gUartProc.recvAvail);
				len = gUartProc.recvAvail;
				recvCmd[len]='\0';
				gUartProc.recvAvail = 0;
				//重新开始接受
				HAL_UART_Receive_IT(&huart4,  (unsigned char *)gUartProc.recvBuf, 1);

				//打开中断，继续接受
				trim((char *)recvCmd);

				printf("rsp>>: %s\r\n", recvCmd);
				if (strcmp(recvCmd, "screenOn") == 0){
					//全部开灯
					HAL_I2C_Master_Transmit(&hi2c1, 0xA0, (uint8_t*)text_full, 34,  1000);
				} else if (strcmp(recvCmd, "screenOff") == 0){
					//全部关灯
					HAL_I2C_Master_Transmit(&hi2c1, 0xA0, (uint8_t*)text_clear, 34,  1000);
				} else if (strcmp(recvCmd, "beep") == 0){
					//蜂鸣器叫一下
					BeepOn(200);
				} else if (strcmp(recvCmd, "scrollOn") == 0){
					//蜂鸣器叫一下
					gUartProc.screenScrollTicks = 0;
					gUartProc.screenScrollEnable = 1;
				} else if (strcmp(recvCmd, "scrollOff") == 0){
					gUartProc.screenScrollEnable = 0;
				}
			}
		}
	}
}


void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.HSIDivValue = RCC_HSI_DIV1;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** RCC Clock Config
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_ACLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_PCLK3|RCC_CLOCKTYPE_PCLK4
                              |RCC_CLOCKTYPE_PCLK5;
  RCC_ClkInitStruct.AXISSInit.AXI_Clock = RCC_AXISSOURCE_HSI;
  RCC_ClkInitStruct.AXISSInit.AXI_Div = RCC_AXI_DIV1;
  RCC_ClkInitStruct.MCUInit.MCU_Clock = RCC_MCUSSOURCE_HSI;
  RCC_ClkInitStruct.MCUInit.MCU_Div = RCC_MCU_DIV1;
  RCC_ClkInitStruct.APB4_Div = RCC_APB4_DIV1;
  RCC_ClkInitStruct.APB5_Div = RCC_APB5_DIV1;
  RCC_ClkInitStruct.APB1_Div = RCC_APB1_DIV1;
  RCC_ClkInitStruct.APB2_Div = RCC_APB2_DIV1;
  RCC_ClkInitStruct.APB3_Div = RCC_APB3_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
PUTCHAR_PROTOTYPE
{
 HAL_UART_Transmit(&huart4,(uint8_t*)&ch,1,HAL_MAX_DELAY);
 return ch;
}
#endif
